package cn.yly.esearch.sql4es.http;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.druid.support.json.JSONUtils;
import com.google.gson.Gson;

import cn.yly.esearch.sql4es.EsTool;

public class EsHttpClient {

    private final List<EsConfig> esConfig;
    
    /**
	 * 当前使用的是第几个连接
	 */
	private volatile int index = 0;


    public  EsHttpClient(List<EsConfig> esConfigs) throws SQLException {
        this.esConfig = esConfigs;
    }
    public String query(String dsl) throws SQLException {
        try {
            return send(esConfig.get(index).getUrl()+"/_search" , "POST", esConfig.get(index).getAuth(), dsl);
        } catch (Exception e) {
            throw new SQLException(e);
        }
    }
    public String delete(String dsl) throws SQLException {
    	try {
    		return send(esConfig.get(index).getUrl()+"/_delete_by_query", "POST", esConfig.get(index).getAuth(), dsl);
    	} catch (Exception e) {
    		throw new SQLException(e);
    	}
    }
    public String update(String dsl,String id) throws SQLException {
    	try {
    		//index/type/id
    		return send(esConfig.get(index).getUrl()+"/"+EsHttpConfig.esType+"/"+id, "POST", esConfig.get(index).getAuth(), dsl);
    	} catch (Exception e) {
    		throw new SQLException(e);
    	}
    }
    /**
     * list:需要添加的数据
     * idkey
     * 数据id字段
     * */
    public String addList(List<Map<String,Object>> list,String idKey) throws SQLException {
    	Map<String,Object> aMap = new HashMap<>();
    	Map<String,String> dMap = new HashMap<>();
    	dMap.put("_index", esConfig.get(index).getIndex());
    	dMap.put("_type", EsHttpConfig.esType);
//    	dMap.put("_id",object.get(idKey).toString());
    	aMap.put("index", dMap);
    	String aMapJson= JSONUtils.toJSONString(aMap);
    	try {
    		StringBuffer sb = new StringBuffer();
    		for (Map<String,Object> object : list) {
            	//数据头
    			sb.append(aMapJson);
        		sb.append("\n");
        		//添加的数据
        		sb.append(JSONUtils.toJSONString(object));
        		sb.append("\n");
			}
    		
    		
    		return send(esConfig.get(index).getUrl()+"/_bulk", "PUT", esConfig.get(index).getAuth(), sb.toString());
    	} catch (Exception e) {
    		throw new SQLException(e);
    	}
    }
    
    /**
     * 添加es索引别名
     * */
    public boolean addEsAlias(String alias) throws SQLException {
    	try {
    		String sDate = "{\"actions\":[{\"add\":{\"index\":\""+esConfig.get(index).getIndex()+"\",\"alias\":\""+alias+"\"}}]}";
    		String json = send(esConfig.get(index).getNoIndexUrl()+"_aliases", "POST", esConfig.get(index).getAuth(), sDate);
    		Map<String,Object> mmap = new Gson().fromJson(json, Map.class);
    		return (boolean) mmap.get("acknowledged");
    	} catch (Exception e) {
    		throw new SQLException(e);
    	}
    }
    
    /**
     * 删除es索引别名
     * */
    public boolean deleteEsAlias(String alias) throws SQLException {
    	try {
    		String sDate = "{\"actions\":[{\"remove\":{\"index\":\""+esConfig.get(index).getIndex()+"\",\"alias\":\""+alias+"\"}}]}";
    		String json = send(esConfig.get(index).getNoIndexUrl()+"_aliases", "POST", esConfig.get(index).getAuth(),sDate);
    		Map<String,Object> mmap = new Gson().fromJson(json, Map.class);
    		return (boolean) mmap.get("acknowledged");
    	} catch (Exception e) {
    		throw new SQLException(e);
    	}
    }
    /**
     * 添加es索引
     * */
    public boolean addEsIndex() throws SQLException {
    	try {
    		String json = send(esConfig.get(index).getUrl(), "PUT", esConfig.get(index).getAuth(), "{}");
    		Map<String,Object> mmap = new Gson().fromJson(json, Map.class);
    		return (boolean) mmap.get("acknowledged");
    	} catch (Exception e) {
    		throw new SQLException(e);
    	}
    }
    /**
     * 删除es索引
     * */
    public boolean deleteEsIndex() throws SQLException {
    	try {
    		String json = send(esConfig.get(index).getUrl(), "DELETE", esConfig.get(index).getAuth(), "{}");
    		Map<String,Object> mmap = new Gson().fromJson(json, Map.class);
    		return (boolean) mmap.get("acknowledged");
    	} catch (Exception e) {
    		throw new SQLException(e);
    	}
    }
    
    
    
    
    
    boolean ping(long timeoutInMs) throws SQLException {
        try {
            send(esConfig.get(index).getUrl(), "HEAD", null, null);
            return true;
        } catch (Exception e) {
            throw new SQLException("Cannot ping server", e);
        }
    }
    /**
     * @param uri
     * @param method
     * @param auth
     * @param body   请求参数，Json串
     * @return
     */
    public String send(String uri, String method, String auth, String body) throws IOException {
    	
        String result = null;
        OutputStream out = null;
        InputStream in = null;
        try {
            URL url = new URL(uri);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setUseCaches(false);
            connection.setReadTimeout(esConfig.get(index).getReadTimeout());
            connection.setConnectTimeout(esConfig.get(index).getConnectTimeout());
            connection.setAllowUserInteraction(false);
            connection.setRequestMethod(EsTool.isEmpty(method) ? "POST" : method);
            connection.setRequestProperty("content-type", "application/json;charset=utf-8");
            if (!EsTool.isEmpty(auth)) {
                connection.setRequestProperty("Authorization", auth);
            }
            connection.connect();// 获取连接

            if (!EsTool.isEmpty(body)) {
                out = connection.getOutputStream();
                out.write(EsTool.bytes(body, StandardCharsets.UTF_8));
                // out.flush();
            }

            in = connection.getInputStream();
            BufferedReader buffer = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));

            StringBuffer sb = new StringBuffer();
            String line = null;
            while ((line = buffer.readLine()) != null) {
                sb.append(line);
            }
            result = sb.toString();

            connection.disconnect();
        } catch (Exception e) {
        	e.printStackTrace();
        	index++;
			if (index == esConfig.size()) {
				/**
				 * es所有连接都不可用
				 */
				throw new RuntimeException("es所有连接都不可用");
			} else {
				return send(uri, method, auth, body);
			}
        } finally {
            try {
                if (null != in)
                    in.close();
                if (null != out)
                    out.close();
            } catch (Exception e2) {
                System.out.println("[关闭流异常][错误信息：" + e2.getMessage() + "]");
            }
        }
        return result;
    }

}
